package com.zkny.zknyerp.config;

import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * shiro配置类
 * @author W360
 *
 */
@Configuration
public class ShiroConfig {


    @Value("${spring.redis.host}")
    private String redisHost;
    @Value("${spring.redis.port}")
    private String redisPort;
    @Value("${spring.redis.password}")
    private String redisPassword;

    //配置redis
    @Bean
    public RedisManager redisManager(){
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(redisHost+":"+redisPort);
        redisManager.setPassword(redisPassword);
        redisManager.setTimeout(2000);
        return redisManager;
    }

    //配置sessionID生成器
    @Bean
    public JavaUuidSessionIdGenerator sessionIdGenerator(){
        return new JavaUuidSessionIdGenerator();
    }

    //配置redissessiondao
    @Bean
    public RedisSessionDAO redisSessionDAO(){
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());//注入redis管理器
        redisSessionDAO.setSessionIdGenerator(sessionIdGenerator());//注入sessionid生成器
        redisSessionDAO.setExpire(3*24*3600);//配置用户登录信息保存时间
        return redisSessionDAO;
    }

    //自定义会话管理器
    @Bean
    public SessionManager sessionManager(){
        MySessionManager mySessionManager = new MySessionManager();
        mySessionManager.setSessionDAO(redisSessionDAO());//配置redisSessionDao
        mySessionManager.setGlobalSessionTimeout(3*24*3600*1000);
        return mySessionManager;
    }

    //cacheManager缓存redis
    @Bean
    public RedisCacheManager redisCacheManager(){
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());//注入redis管理器
        redisCacheManager.setPrincipalIdFieldName("userId");
        return redisCacheManager;
    }

    //配置shiro加密
    @Bean
    public CredentialsMatcher getCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //设置密码散列次数
        credentialsMatcher.setHashIterations(2);
        //设置加密方式
        credentialsMatcher.setHashAlgorithmName("md5");
        return credentialsMatcher;
    }

    //获取realm
    @Bean
    public Realm getRealm() {
        UserRealms realms = new UserRealms();
        //设置密码器
        realms.setCredentialsMatcher(getCredentialsMatcher());
        return realms;
    }

    //配置安全管理器
    @Bean
    public SecurityManager getSecurityManager() {

        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(getRealm());//将realm注入到安全管理器中
        securityManager.setSessionManager(sessionManager());//注入会话管理器
        securityManager.setCacheManager(redisCacheManager());
        return securityManager;
    }

    //配置认证过滤器
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //注入安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //--------------注册自定义认证过滤器开始-----------------
        // 1、创建过滤器Map，用来装自定义过滤器
        LinkedHashMap<String, Filter> m = new LinkedHashMap<>();
        // 2、将自定义过滤器放入map中，如果实现了自定义授权过滤器，那就必须在这里注册，否则Shiro不会使用自定义的授权过滤器
        m.put("authc", new ShiroLoginFilter());
        // 3、将过滤器Ma绑定到shiroFilterFactoryBean上
        shiroFilterFactoryBean.setFilters(m);
        //--------------注册自定义认证过滤器结束-----------------

        Map<String, String> map = new LinkedHashMap<String, String>();
        //定义过滤链
        //static下的不需要认证
        map.put("/css/**","anon");
        map.put("/images/**","anon");
        map.put("/js/**","anon");
        map.put("/echarts/**","anon");
        map.put("/layui/**","anon");
        //webapp下login.html不认证
        map.put("/login.html", "anon");
        map.put("/api/user/login", "anon");
        map.put("/api/device/getAppDevice", "anon");
        map.put("/api/device/getDevkey", "anon");
        //webapp下css不认证
        map.put("/css/**", "anon");
        //webapp下images不认证
        map.put("/images/**", "anon");
        //配置后台管理登录界面不拦截
        //对所有用户认证
        map.put("/**", "authc");
        //map.put("/**", "anon");
        //登录
        shiroFilterFactoryBean.setLoginUrl("/login.html");
        //首页
        shiroFilterFactoryBean.setSuccessUrl("/map.html");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    @Bean(name="lifecycleBeanPostProcessor")
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
    /**
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
     *
     * @return
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(getSecurityManager());
        return authorizationAttributeSourceAdvisor;
    }
}
